package com.demo.security.impl;

import java.util.ArrayList;
import java.util.List;

import com.demo.security.access.model.SecurityResource;
import com.demo.security.expression.ExpressionMetadataAnalyzer;
import com.demo.security.expression.SourceResolverHandler;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PrePostInvocationAttributeFactory;
import org.springframework.util.Assert;

/**
 * 表达式元数据分解器处理器
 * 
 * @author ryuu.kk
 */
public class ExpressionSourceResolverHandler implements SourceResolverHandler {
	
	/**
	 * PrePost属性工厂
	 */
	private PrePostInvocationAttributeFactory prePostAttributeFactory;

	@Override
	public List<ConfigAttribute> createConfigAttribute(SecurityResource sr) {
		
		// ~
		Assert.notNull(sr, "SecurityResource can not empty.");
		String exps = sr.getExpression();
		Assert.notNull(exps, "expression can not empty.");
		
		List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>();
		//if (StringUtils.isEmpty(resolver)) {
		//	//default
		//	resolver = SourceResolverHandler.RESOLVER_SPEL;
		//}
		
		// PrePostModel
		//if (SourceResolverHandler.RESOLVER_SPEL.equals(resolver)) {
		if (this.prePostAttributeFactory == null) {
			prePostAttributeFactory = new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler());
		}
		String preFilterAttribute = null;
		String filterObject = null;
		String preAuthorizeAttribute = null;
		String postFilterAttribute = null;
		String postAuthorizeAttribute = null;
		//Pre 
		PreInternallyExpressionMetadataAnalyzer	preAnalyzer = new PreInternallyExpressionMetadataAnalyzer(exps);
		if (preAnalyzer.analyze() != null) {
			filterObject = preAnalyzer.getFilterObject();
			preFilterAttribute = preAnalyzer.getPreFilterAttribute();
			preAuthorizeAttribute = preAnalyzer.getPreAuthorizeAttribute();
			PreInvocationAttribute pre = this.prePostAttributeFactory.createPreInvocationAttribute(preFilterAttribute,
																			filterObject, preAuthorizeAttribute);
			if (pre != null) {
				attrs.add(pre);
			}	
		}
		
		//Post
		PostInternallyExpressionMetadataAnalyzer postAnalyzer = new PostInternallyExpressionMetadataAnalyzer(exps);
		if (postAnalyzer.analyze() != null) {
			postFilterAttribute = postAnalyzer.getPostFilterAttribute();
			postAuthorizeAttribute = postAnalyzer.getPostAuthorizeAttribute();
			PostInvocationAttribute post = this.prePostAttributeFactory.createPostInvocationAttribute(postFilterAttribute,
																			postAuthorizeAttribute);
			if (post != null) {
				attrs.add(post);
			}
		}

		((ArrayList<ConfigAttribute>) attrs).trimToSize();
		
		// 垃圾回收
		preAnalyzer = null;
		postAnalyzer = null;
		//}
		return attrs;
	}

	public void setPrePostAttributeFactory(PrePostInvocationAttributeFactory prePostAttributeFactory) {
		this.prePostAttributeFactory = prePostAttributeFactory;
	}


	/**
	 * 内置Pre表达式分解器
	 * 
	 * @author ryuu.kk
	 */
	private class PreInternallyExpressionMetadataAnalyzer implements ExpressionMetadataAnalyzer {
		
		/**
		 * 表达式
		 */
		private String expression = null;
		
		/**
		 * 目标类
		 */
		private String filterObject = null;
		
		/**
		 * 前置过滤属性
		 */
		private String preFilterAttribute = null;
		/**
		 * 前置权限属性
		 */
		private String preAuthorizeAttribute = null;
        /**
         * 构造方法
         * @param expression 表达式
         */
		public PreInternallyExpressionMetadataAnalyzer(String expression) {
			this.expression = expression;
		}

		@Override
		public List<String> analyze() {
			Assert.notNull(expression);
			if (!support()) {
				return null;
			}
			List<String> expList = new ArrayList<String>(2);
			//@PreFilter("hasPermission(#projectId, 'com.loanclub.model.Project',read)");
			//@PreAuthorize("hasPermission(#projectId, 'com.loanclub.model.Project',admin)");
			int preFilterIndex = expression.indexOf("@PreFilter");
			int preAuthorizeIndex = expression.indexOf("@PreAuthorize");
			
			if (preFilterIndex != -1) {
				String value = expression.substring(expression.indexOf("(") + 2, expression.lastIndexOf(")") - 1);
				int valueIndex = value.indexOf("="); 
				if (valueIndex != -1) {
					value = value.substring(valueIndex + 1);
				}
				this.preFilterAttribute = value.trim();
				expList.add(preFilterAttribute);
			}			
			if (preAuthorizeIndex != -1) {
				String value = expression.substring(expression.indexOf("(") + 2, expression.lastIndexOf(")") - 1);
				int valueIndex = value.indexOf("="); 
				if (valueIndex != -1) {
					value = value.substring(valueIndex + 1);
				}
				this.preAuthorizeAttribute = value.trim();
				expList.add(preAuthorizeAttribute);
			}
			return expList.isEmpty() ? null : expList;
		}

		@Override
		public boolean support() {
			Assert.notNull(expression);
			return expression.startsWith("@Pre");
		}

		public String getFilterObject() {
			return this.filterObject;
		}

		public String getPreFilterAttribute() {
			return this.preFilterAttribute;
		}

		public String getPreAuthorizeAttribute() {
			return this.preAuthorizeAttribute;
		}
	}
	
	/**
	 * 内置Post表达式分解器
	 * @author ryuu.kk
	 *
	 */
	private class PostInternallyExpressionMetadataAnalyzer implements ExpressionMetadataAnalyzer {
		
		/**
		 * 表达式
		 */
		private String expression;
		
		/**
		 * 后置过滤属性
		 */
		private String postFilterAttribute;
		
		/**
		 * 后置权限属性
		 */
		private String postAuthorizeAttribute;
		
		/**
		 * 构造方法
		 * @param expression 表达式
		 */
		private PostInternallyExpressionMetadataAnalyzer(String expression) {
			this.expression = expression;
		}
		
		@Override
		public List<String> analyze() {
			Assert.notNull(expression);
			if (!support()) {
				return null;
			}
			List<String> expList = new ArrayList<String>(2);
			//@PostFilter("hasPermission(#projectId, 'com.loanclub.model.Project',read)")
			//@PostAuthorize("hasPermission(#projectId, 'com.loanclub.model.Project',read)")
			int postFilterIndex = expression.indexOf("@PostFilter");
			int postAuthorizeIndex = expression.indexOf("@PostAuthorize");
			
			if (postFilterIndex != -1) {
				String value = expression.substring(expression.indexOf("(") + 2, expression.lastIndexOf(")") - 1);
				int valueIndex = value.indexOf("="); 
				if (valueIndex != -1) {
					value = value.substring(valueIndex + 1);
				}
				this.postFilterAttribute = value.trim();
				expList.add(postFilterAttribute);
			}			
			if (postAuthorizeIndex != -1) {
				String value = expression.substring(expression.indexOf("(") + 2, expression.lastIndexOf(")") - 1);
				int valueIndex = value.indexOf("="); 
				if (valueIndex != -1) {
					value = value.substring(valueIndex + 1);
				}
				this.postAuthorizeAttribute = value.trim();
				expList.add(postAuthorizeAttribute);
			}
			
			return expList.isEmpty() ? null : expList;
		}

		@Override
		public boolean support() {
			Assert.notNull(expression);
			return expression.startsWith("@Post");
		}

		public String getPostFilterAttribute() {
			return postFilterAttribute;
		}

		public String getPostAuthorizeAttribute() {
			return postAuthorizeAttribute;
		}
	}
}
